#pragma once

#ifndef _SERVER_SYSTEM_CLIENT_HANDLER_H_
#define _SERVER_SYSTEM_CLIENT_HANDLER_H_

#include "ServerSystem/SystemHandler.h"
#include "Core/Packages.h"

#include "Poco/Event.h"

namespace ExamSystem
{
    using Poco::SharedPtr;
    using Poco::BasicEvent;

    class CXMLConnection;

namespace Server
{

    class CServerSystem;
    
    /**************************************************************************\
     Component:     CClientServerHandler
     Description:
        This class manages a connection to the connected servers. It 
        has a FSM to record the states.

        As this class manages only one connection, so the server should create
        an instance for each connection.
    \**************************************************************************/
    class CClientServerHandler : public CSystemHandler
    {
    public:
        CClientServerHandler(
            CServerSystem *serverSystem,
            const SharedPtr<CXMLConnection> &connection,
            int localID
            );
        ~CClientServerHandler(void);

    public:
        // start the FSM
        virtual void StartHandler(void);

    public:
        int GetLocalID(void) const;

    protected:
        // register sensitive package types
        virtual void RegisterPackageTypes(void);

        // process received package
        virtual void ProcessPackage(void);

    public:
        // events
        BasicEvent<void *const> eventVersionCheckFailed;
        BasicEvent<void *const> eventFailedToSendDatabase;
        //BasicEvent<CServerInfoPackage> eventServerInfoUpdated;
        BasicEvent<CConnectionInfoPackage> eventConnectionInfoUpdated;
        BasicEvent<void *const> eventReady;

    protected:
        // package handlers
        void ResultPackageHandler(void);
        void VersionPackageHandler(void);
        void ServerInfoPackageHandler(void);
        void ConnectionInfoPackageHandler(void);
        void DatabasePackageHandler(void);

        // sub-handler
        void SystemVersionCheckPackageHandler(void);
        void DatabaseVersionCheckPackageHandler(void);
        void SendingDatabaseResultPackageHandler(void);

    protected:
        enum ConnectionState {
            stateReady,
            stateVersionCheck,
            stateDatabaseCheck,
            stateSendindDatabase,
            stateRedirecting,
            stateError
        };
        ConnectionState m_presentState;
        
        // times we have tried to send database file
        int m_nRetrySendingDatabase;
        enum { maxRetryTime = 3 };

        int m_localID;

        typedef void (CClientServerHandler::*PackageHandler)(void);
        std::map<std::string, PackageHandler> m_packageHandlers;

        static unsigned int ms_clientServerId;
    };

    
    /**************************************************************************\
     Component:     CClientHandler
     Description:
        This class manages a connection to the connected clients. It 
        has a FSM to record the states.
    \**************************************************************************/
    class CClientHandler : public CSystemHandler
    {
    public:
        CClientHandler(
            CServerSystem *serverSystem, 
            const SharedPtr<CXMLConnection> &connection, 
            int localID
            );
        ~CClientHandler(void);

    public:
        // start the FSM
        virtual void StartHandler(void);

    public:
        int GetLocalID(void) const;

    protected:
        // register sensitive package types
        virtual void RegisterPackageTypes(void);

        // process received package
        virtual void ProcessPackage(void);

    public:
        // events
        BasicEvent<void *const> eventVersionCheckFailed;
        BasicEvent<CConnectionInfoPackage> eventConnectionInfoUpdated;
        BasicEvent<void *const> eventReady;

    protected:
        // package handlers
        void ResultPackageHandler(void);
        void VersionPackageHandler(void);
        void LoginPackageHandler(void);
        void ConnectionInfoPackageHandler(void);
        void QuestionQueryPackageHandler(void);
        void CriterionQueryPackageHandler(void);
        void DatabasePackageHandler(void);

        // sub-handlers
        void StudentLoginHandler(void);
        void InvigilatorLoginHandler(void);

        // questions and criterions
        void PrepareQuestions(void);
        void PrepareCriterions(void);
        void SendNextQuestionCriterion(bool flagResend);

    protected:
        enum ConnectionState {
            stateReady,
            stateVersionCheck,
            stateWaitForLogin,
            stateWaitForInvigilator,
            stateRedirecting,
            stateSendingQuestions,
            stateSendingCriterions,
            stateError
        };
        ConnectionState m_presentState;

        int m_localID;

        typedef void (CClientHandler::*PackageHandler)(void);
        std::map<std::string, PackageHandler> m_packageHandlers;

        std::vector<int> m_questionIds[QuestionTypeCount];
        int m_currentSendingType;
        int m_currentSendingIdx;

        static unsigned int ms_clientId;
    };
}
}
#endif